package com.inforich.common.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @description: some desc
 * @author: HJM
 * @date: 2022/10/28
 */
public class JsonUtil {

  private JsonUtil() {
  }

  public static String toJson(Object obj) {
    return JSON.toJSONString(obj);
  }

  public static <T> T parseObject(String json, Class<T> clazz) {
    return JSON.parseObject(json, clazz);
  }

  public static List<String> toJsonList(Collection<?> values) {
    if (values == null) {
      return null;
    }

    List<String> result = new ArrayList<String>();
    for (Object obj : values) {
      result.add(toJson(obj));
    }
    return result;
  }

  public static <T> List<T> parseJsonList(List<String> list, Class<T> clazz) {
    if (list == null) {
      return null;
    }
    List<T> result = new ArrayList<T>();
    for (String s : list) {
      result.add(parseObject(s, clazz));
    }
    return result;
  }

  /**
   * 得到json中string类型的值
   */
  public static String getString(JSONObject jo, String key) {
    if (jo == null) {
      return "";
    }
    if (jo.containsKey(key)) {
      return jo.get(key).toString();
    }
    return "";
  }

  /**
   * 得到json中string类型的值
   */
  public static String getString(JSONObject jo, String key, String defaultVal) {
    if (jo == null) {
      return defaultVal;
    }
    if (jo.containsKey(key)) {
      return "".equals(jo.get(key).toString()) ? defaultVal : jo.get(key).toString();
    }
    return defaultVal;
  }

  /**
   * 检查json对象是否全部包含keys
   *
   * @param jsonObject 对象
   * @param keys       key值
   * @return false if one key is not exists
   */
  public static boolean checkString(JSONObject jsonObject, List<String> keys) {
    for (String key : keys) {
      if (StrUtil.isBlank(jsonObject.getString(key))) {
        return false;
      }
    }
    return true;
  }

  /**
   * 以int形式返回JSONObject中的值
   */
  public static Integer getInt(JSONObject jsonObject, String key, Integer defaultVal) {
    int defaultValue = 0;
    if (defaultVal != null) {
      defaultValue = defaultVal;
    }
    return jsonObject.containsKey(key) ? ("".equals(jsonObject.getString(key)) ? defaultValue
        : jsonObject.getInteger(key)) : defaultValue;
  }

  public static Integer getInt(JSONObject jsonObject, String key) {
    return getInt(jsonObject, key, null);
  }

  /**
   * 以int形式返回JSONObject中的值
   */
  public static Integer getIntDefault(JSONObject jsonObject, String key, Integer defaultVal) {
    return jsonObject.getInteger(key) == null ? defaultVal : jsonObject.getInteger(key);
  }

  public static Double getDouble(JSONObject jsonObject, String key) {
    return getDouble(jsonObject, key, null);
  }

  /**
   * 以Double形式返回JSONObject中的值
   */
  public static Double getDouble(JSONObject jsonObject, String key, Double defaultVal) {
    double defaultValue = 0.0;
    if (defaultVal != null) {
      defaultValue = defaultVal;
    }
    return jsonObject.containsKey(key) ? ("".equals(jsonObject.getString(key)) ? defaultValue
        : jsonObject.getDouble(key)) : defaultValue;
  }

  /**
   * 判断json是否为空
   */
  public static boolean isEmpty(JSONObject json) {
    return null == json || json.isEmpty();
  }

  /**
   * 判断json是否为空
   */
  public static boolean isNotEmpty(JSONObject json) {
    return !isEmpty(json);
  }

  public static JSONObject of(String key, Object value) {
    JSONObject json = new JSONObject();
    json.put(key, value);
    return json;
  }

  public static JSONObject of(String k1, Object v1, String k2, Object v2) {
    return fromEntries(entryOf(k1, v1), entryOf(k2, v2));
  }

  public static JSONObject of(String k1, Object v1, String k2, Object v2, String k3, Object v3) {
    return fromEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
  }

  public static JSONObject of(String k1, Object v1, String k2, Object v2, String k3, Object v3,
      String k4, Object v4) {
    return fromEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4));
  }

  @SafeVarargs
  private static JSONObject fromEntries(Entry<String, Object>... entries) {
    JSONObject json = new JSONObject();
    for (Entry<String, Object> entry : entries) {
      json.put(entry.getKey(), entry.getValue());
    }
    return json;
  }

  private static SimpleEntry<String, Object> entryOf(String key, Object value) {
    return new SimpleEntry<>(key, value);
  }

  static class SimpleEntry<String, Object> implements Entry<String, Object>, java.io.Serializable {

    private final String key;
    private final Object value;

    SimpleEntry(String key, Object value) {
      this.key = key;
      this.value = value;
    }

    @Override
    public String getKey() {
      return key;
    }

    @Override
    public Object getValue() {
      return value;
    }

    @Override
    public Object setValue(java.lang.Object value) {
      throw new UnsupportedOperationException();
    }
  }

  public static Builder builder() {
    return new Builder();
  }

  public static Builder builder(boolean ordered) {
    return new Builder(ordered);
  }

  public static class Builder {

    JSONObject map;

    public Builder() {
    }

    public Builder(boolean ordered) {
      if (ordered) {
        map = new JSONObject();
      }
    }

    public Builder put(String key, Object value) {
      if (map == null) {
        map = new JSONObject();
      }
      map.put(key, value);
      return this;
    }

    public Builder putAll(Map<String, Object> paramMap) {
      map.putAll(paramMap);
      return this;
    }

    public JSONObject build() {
      return map;
    }
  }

  public static boolean hasEmpty(JSONObject json, String... keys) {
    if (null != json) {
      for (String key : keys) {
        if (StrUtil.isBlank(json.getString(key))) {
          return true;
        }
      }
    }
    return false;
  }

  public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
    Map<Object, Boolean> map = new ConcurrentHashMap<>();
    return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
  }

  /**
   * JSON->MAP
   */
  public static Map<String, Object> toMap(JSONObject json) {
    Map<String, Object> map = new HashMap<>();
    json.forEach(map::put);
    return map;
  }

}
